home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / Mac OS USB DDK_v1.0.1 / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-03  |  12.0 KB  |  349 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <DriverServices.h>
  16. #include <USB.h>
  17.  
  18. #include "MouseModule.h"
  19.  
  20. usbMousePBStruct myMousePB;
  21.  
  22. void InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  23. {
  24.     paramblock->usbReference = theDeviceRef;
  25.     paramblock->pbVersion = kUSBCurrentPBVersion;
  26.     paramblock->usbWIndex = 0;             
  27.     paramblock->usbBuffer = nil;        
  28.     paramblock->usbStatus = noErr;
  29.     paramblock->usbReqCount = 0;
  30.     paramblock->usbWValue = 0;
  31.     paramblock->usbFlags = 0;
  32. }
  33.  
  34.  
  35.  
  36. Boolean immediateError(OSStatus err)
  37. {
  38.     return((err != kUSBPending) && (err != noErr) );
  39. }
  40.  
  41. void MouseModuleInitiateTransaction(USBPB *pb)
  42. {
  43. register usbMousePBStruct *pMousePB;
  44. OSStatus myErr;
  45.  
  46.     pMousePB = (usbMousePBStruct *)(pb);
  47.     pMousePB->transDepth++;
  48.     if (pMousePB->transDepth < 0)
  49.     {
  50.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth < 0 (initiation)", pMousePB->pb.usbRefcon );
  51.     }
  52.     
  53.     if (pMousePB->transDepth > 1)
  54.     {
  55.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth > 1 (initiation)", pMousePB->pb.usbRefcon );
  56.     }
  57.     
  58.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  59.     {
  60.         case kGetFullConfiguration:
  61.             InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  62.             
  63.             pMousePB->pb.usbRefcon |= kCompletionPending;
  64.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  65.             myErr = USBGetFullConfigurationDescriptor(pb);
  66.             if(immediateError(myErr))
  67.             {
  68.                 USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, "\pUSBHIDMouseModule: kGetFullConfiguration (ImmediateError)", myErr);
  69.             }
  70.             break;
  71.             
  72.         case kFindInterfaceAndSetProtocol:
  73.             myErr = FindHIDInterfaceByNumber(pMousePB->pFullConfigDescriptor, pMousePB->interfaceDescriptor.interfaceNumber, &pMousePB->pInterfaceDescriptor );    // find the HID interface
  74.             if ((pMousePB->pInterfaceDescriptor == NULL) || (myErr != noErr))
  75.             {
  76.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Interface not found", myErr);
  77.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  78.             }
  79.             
  80.             InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  81.             
  82.             pMousePB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  83.             pMousePB->pb.usbBRequest = kHIDRqSetProtocol;
  84.             pMousePB->pb.usbWValue = kHIDBootProtocolValue; 
  85.             pMousePB->pb.usbWIndex = pMousePB->pInterfaceDescriptor->interfaceNumber;
  86.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  87.             
  88.             pMousePB->pb.usbRefcon |= kCompletionPending;
  89.             myErr = USBDeviceRequest(&pMousePB->pb);
  90.             if (immediateError(myErr))
  91.             {
  92.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kSetProtocol (ImmediateError)", myErr);
  93.             }
  94.             break;
  95.             
  96.         case kSetIdleRequest:
  97.             InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  98.             
  99.             pMousePB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  100.             
  101.             pMousePB->pb.usbBRequest = kHIDRqSetIdle;
  102.             if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x1452)) &&
  103.                 (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x0301)) &&
  104.                 (pMousePB->deviceDescriptor.devRel == USB_CONSTANT16(0x0004)))
  105.             {
  106.                 pMousePB->pb.usbWValue = ((50/4)<<8);                 // force a read completion if idle for more than 50ms
  107.             }
  108.             else
  109.             {
  110.                 pMousePB->pb.usbWValue = 0;                         // Turn off SetIdle time (set it to 0ms)
  111.             }
  112.             pMousePB->pb.usbWIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  113.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  114.             
  115.             pMousePB->pb.usbRefcon |= kCompletionPending;
  116.  
  117.             myErr = USBDeviceRequest(&pMousePB->pb);
  118.             if(immediateError(myErr))
  119.             {
  120.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kSetIdleRequest - immediate error", myErr);
  121.             }
  122.             break;
  123.  
  124.         case kFindAndOpenInterruptPipe:
  125.             pMousePB->pb.usbClassType = kUSBInterrupt;
  126.             pMousePB->pb.usbOther = 0;            
  127.             pMousePB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  128.             pMousePB->pb.usbFlags = kUSBIn;
  129.             pMousePB->pb.usbBuffer = pMousePB->pInterfaceDescriptor;
  130.             pMousePB->pb.usbReqCount = (UInt8*)pMousePB->pInterfaceDescriptor - (UInt8*)pMousePB->pFullConfigDescriptor;
  131.             myErr = USBFindNextEndpointDescriptorImmediate( &pMousePB->pb );
  132.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  133.             {
  134.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Endpoint not found", myErr);
  135.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  136.             }
  137.             else
  138.             {
  139.                 pMousePB->pEndpointDescriptor = (USBEndPointDescriptorPtr) pMousePB->pb.usbBuffer;
  140.  
  141.                 InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  142.                 
  143.                 pMousePB->pb.usbFlags = kUSBIn;
  144.                 pMousePB->pb.usbWValue = USBToHostWord(pMousePB->pEndpointDescriptor->maxPacketSize);
  145.                 pMousePB->pb.usbClassType = kUSBInterrupt;
  146.                 pMousePB->pb.usbOther = (pMousePB->pEndpointDescriptor->endpointAddress & 0x0f);
  147.                 pMousePB->pb.usbRefcon |= kCompletionPending;
  148.                 pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  149.         
  150.                 myErr = USBOpenPipe( &pMousePB->pb );
  151.                 if(immediateError(myErr))
  152.                 {
  153.                     USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: USBOpenPipe Failed (ImmediateError)", myErr);
  154.                 }
  155.             }
  156.             break;
  157.         
  158.         case kReadInterruptPipe:
  159.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  160.  
  161.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  162.             pMousePB->pb.usbReqCount = USBToHostWord(pMousePB->pEndpointDescriptor->maxPacketSize);
  163.             pMousePB->pb.usbWIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  164.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  165.             
  166.             pMousePB->pb.usbRefcon |= kCompletionPending;
  167.         
  168.             myErr = USBIntRead(&pMousePB->pb);
  169.             if(immediateError(myErr))
  170.             {
  171.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Read Interrupt Pipe (ImmediateError)", myErr);
  172.             }
  173.             break;
  174.             
  175.         default:
  176.             USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  177.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  178.             break;
  179.     }
  180.     
  181. // At this point the control is returned to the system.  If a USB transaction
  182. // has been initiated, then it will call the Complete procs
  183. // (below) to handle the results of the transaction.
  184. }
  185.  
  186.  
  187. void TransactionCompletionProc(USBPB *pb)
  188. {
  189. register usbMousePBStruct *pMousePB;
  190. unsigned char    * errstring;
  191. USBPipeState     pipeState;
  192.  
  193.     pMousePB = (usbMousePBStruct *)(pb);
  194.     pMousePB->transDepth--;
  195.     if (pMousePB->transDepth < 0)
  196.     {
  197.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth < 0 (completion)", pMousePB->pb.usbRefcon );
  198.     }
  199.     
  200.     if (pMousePB->transDepth > 1)
  201.     {
  202.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth > 1 (completion)", pMousePB->pb.usbRefcon );
  203.     }
  204.     
  205.     if(pMousePB->pb.usbStatus != noErr)                                                        // was there an error?
  206.     {
  207.         switch(pMousePB->pb.usbRefcon & 0x0fff)                                                // yes, so show where the error occurred
  208.         {
  209.             case kGetFullConfiguration:          errstring = "\pUSBHIDMouseModule: Error during GetFullConfiguration"; break;
  210.             case kFindInterfaceAndSetProtocol:    errstring = "\pUSBHIDMouseModule: Error during FindInterfaceAndSetProtocol"; break;
  211.             case kSetIdleRequest:                errstring = "\pUSBHIDMouseModule: Error during kSetIdleRequest"; break;
  212.             case kFindAndOpenInterruptPipe:      errstring = "\pUSBHIDMouseModule: Error during FindAndOpenInterruptPipe"; break;
  213.             case kReadInterruptPipe:              errstring = "\pUSBHIDMouseModule: Error during ReadInterruptPipe"; break;
  214.             default:                              errstring = "\pUSBHIDMouseModule: Error occurred, but state is unknown"; break;
  215.         };
  216.         USBExpertFatalError(pMousePB->deviceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & 0x0fff));
  217.         
  218.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  219.         pMousePB->pb.usbRefcon |= kRetryTransaction;
  220.         pMousePB->retryCount--;
  221.         
  222.         if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon&pMousePB->pb.usbRefcon & 0x0fff) == kSetIdleRequest))
  223.         {
  224.             USBExpertStatus(pMousePB->deviceRef, "\pUSBHIDMouseModule: Device doesn't accept SetIdle", pMousePB->deviceRef);
  225.             pMousePB->pb.usbRefcon = kFindAndOpenInterruptPipe;
  226.             pMousePB->pb.usbStatus = noErr;
  227.         }
  228.         else
  229.         {
  230.             if ((!pMousePB->retryCount)    || (pMousePB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  231.             {                                                                                // or received an abort?
  232.                 USBExpertStatus(pMousePB->deviceRef, "\pUSBHIDMouseModule: Pipe abort or unable to recover from error", pMousePB->deviceRef);
  233.                 pMousePB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  234.             }
  235.             else                                                                            // if it didn't abort and there's retries left, then...
  236.             {
  237.                 if (pMousePB->pipeRef)                                                        // check if the pipe is open.
  238.                 {
  239.                     USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                // yes, so what it's state?
  240.                     if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  241.                     {
  242.                         USBExpertStatus(pMousePB->deviceRef, "\pUSBHIDMouseModule: Pipe is open and stalled, clearing stall...", pMousePB->deviceRef);
  243.                         USBClearPipeStallByReference(pMousePB->pipeRef);
  244.                     }
  245.                 }
  246.             }
  247.         }
  248.     }
  249.     else
  250.     {
  251.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  252.         pMousePB->retryCount = kMouseRetryCount;
  253.     }
  254.  
  255.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  256.     {                                                
  257.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  258.         switch(pMousePB->pb.usbRefcon)
  259.         {
  260.             case kGetFullConfiguration:
  261.                 pMousePB->pFullConfigDescriptor = pMousePB->pb.usbBuffer;
  262.                 if (pMousePB->pFullConfigDescriptor == nil)
  263.                 {
  264.                     USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, "\pUSBHIDMouseModule: USBGetFullConfiguration - pointer is nil", pMousePB->pb.usbRefcon);
  265.                     pMousePB->pb.usbRefcon = kReturnFromDriver;
  266.                 }
  267.                 else
  268.                 {
  269.                     pMousePB->pb.usbRefcon = kFindInterfaceAndSetProtocol;
  270.                 }
  271.                 break;
  272.                 
  273.             case kFindInterfaceAndSetProtocol:
  274.                 pMousePB->pb.usbRefcon = kSetIdleRequest;
  275.                 break;
  276.                 
  277.             case kSetIdleRequest:
  278.                 pMousePB->pb.usbRefcon = kFindAndOpenInterruptPipe;
  279.                 break;
  280.                 
  281.             case kFindAndOpenInterruptPipe:
  282.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  283.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  284.                 break;
  285.                 
  286.             case kReadInterruptPipe:
  287.                 NotifyRegisteredHIDUser(pMousePB->hidDeviceType, pMousePB->hidReport);
  288.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  289.                 break;
  290.  
  291.         }
  292.     }
  293.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver))
  294.         MouseModuleInitiateTransaction(pb);
  295. }
  296.  
  297.  
  298. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBDeviceRef device)
  299. {
  300. #pragma unused (interfacenum)
  301.  
  302. static Boolean beenThereDoneThat = false;
  303.  
  304.     if(beenThereDoneThat)
  305.     {
  306.         USBExpertFatalError(device, kUSBInternalErr, "\pUSBHIDMouseModule is not reentrant", 0);
  307.         return;
  308.     }
  309.     beenThereDoneThat = true;
  310.     
  311. //    DebugStr("\pIn Mouse Interface Entry routine");
  312.  
  313.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  314.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;                
  315.     myMousePB.transDepth = 0;                            
  316.     myMousePB.retryCount = kMouseRetryCount;
  317.       
  318.     myMousePB.pSHIMInterruptRoutine = nil;
  319.     myMousePB.pSavedInterruptRoutine = nil;
  320.  
  321.     myMousePB.deviceRef = device;        
  322.     myMousePB.interfaceRef = nil;        
  323.     myMousePB.pipeRef = nil;        
  324.     
  325.     InitParamBlock(device, &myMousePB.pb);
  326.     
  327.     myMousePB.pb.usbReference = device;
  328.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  329.     myMousePB.pb.usbRefcon = kGetFullConfiguration;        
  330.     
  331.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  332.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  333.     {
  334.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  335.     }
  336.     else
  337.     {
  338.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  339.     }
  340.     
  341.     myMousePB.pCursorDeviceInfo = 0;                
  342.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  343.  
  344.     MouseModuleInitiateTransaction(&myMousePB.pb);
  345. }
  346.  
  347.  
  348.  
  349.